package cn.jbolt.admin.monitor;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.setting.GroupedMap;
import cn.hutool.system.oshi.OshiUtil;
import cn.jbolt.core.api.JBoltApiBaseController;
import cn.jbolt.core.api.httpmethod.JBoltHttpGet;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.core.cache.JBoltCacheType;
import cn.jbolt.core.permission.CheckPermission;
import cn.jbolt.core.permission.OnlySaasPlatform;
import cn.jbolt.core.permission.UnCheckIfSystemAdmin;
import cn.jbolt.core.util.JBoltDateUtil;
import cn.jbolt.core.util.JBoltIpUtil;
import cn.jbolt.extend.permission.PermissionKey;
import com.alibaba.fastjson.JSON;
import com.jfinal.core.Path;
import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import oshi.hardware.CentralProcessor;
import oshi.hardware.CentralProcessor.TickType;
import oshi.hardware.GlobalMemory;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@UnCheckIfSystemAdmin
@OnlySaasPlatform
@CheckPermission(PermissionKey.JBOLT_SERVER_MONITOR)
@Path("/api/admin/serverMonitor")
public class ServerMonitorAdminController extends JBoltApiBaseController {
    /**
     * 磁盘监控
     */
    @JBoltHttpGet
    public void disk() {
        FileSystem fileSystem = OshiUtil.getOs().getFileSystem();
        List<OSFileStore> fsList = fileSystem.getFileStores();
        List<Kv> disks=new ArrayList<Kv>();
        Kv kv;
        for(OSFileStore fs:fsList) {
            kv=Kv.create();
            kv.set("name",fs.getName());
            kv.set("label",fs.getLabel());
            kv.set("dirName",fs.getMount());
            kv.set("sysTypeName",fs.getType());
            kv.set("total", FileUtil.readableFileSize(fs.getTotalSpace()));
            kv.set("free",FileUtil.readableFileSize(fs.getFreeSpace()));
            kv.set("usable",FileUtil.readableFileSize(fs.getUsableSpace()));
            kv.set("used",FileUtil.readableFileSize(fs.getTotalSpace()-fs.getUsableSpace()));
            if((fs.getTotalSpace()-fs.getUsableSpace())==0) {
                kv.set("usedRate","100%");
            }else {
                kv.set("usedRate", NumberUtil.mul(NumberUtil.toBigDecimal(fs.getTotalSpace()-fs.getUsableSpace()).divide(NumberUtil.toBigDecimal(fs.getTotalSpace()),2, RoundingMode.HALF_UP).doubleValue(), 100));
            }
            disks.add(kv);
        }
        renderJBoltApiSuccessWithData(disks);
    }

    /**
     * 内存监控
     */
    @JBoltHttpGet
    public void memory() {
        Kv datas = Kv.create();
        GlobalMemory memory = OshiUtil.getMemory();
        long total=memory.getTotal();
        long free=memory.getAvailable();
        long uesd=total-free;
        datas.set("memoryTotal", NumberUtil.div(NumberUtil.toBigDecimal(total),NumberUtil.toBigDecimal(1024 * 1024 * 1024), 2));
        datas.set("memoryUsed", NumberUtil.div(NumberUtil.toBigDecimal(uesd),NumberUtil.toBigDecimal(1024 * 1024 * 1024), 2));
        datas.set("memoryFree", NumberUtil.div(NumberUtil.toBigDecimal(free),NumberUtil.toBigDecimal(1024 * 1024 * 1024), 2));
        if(uesd==0) {
            datas.set("memoryRate","0%");
        }else {
            datas.set("memoryRate", NumberUtil.mul(NumberUtil.toBigDecimal(uesd).divide(NumberUtil.toBigDecimal(total),2, RoundingMode.HALF_UP).doubleValue(), 100));
        }
        long jvmTotal=Runtime.getRuntime().totalMemory();
        long jvmFree=Runtime.getRuntime().freeMemory();
        long jvmUsed=jvmTotal-jvmFree;
        datas.set("jvmMemoryTotal",  NumberUtil.div(NumberUtil.toBigDecimal(jvmTotal),NumberUtil.toBigDecimal(1024 * 1024), 2));
        datas.set("jvmMemoryUsed",  NumberUtil.div(NumberUtil.toBigDecimal(jvmUsed),NumberUtil.toBigDecimal(1024 * 1024), 2));
        datas.set("jvmMemoryFree",  NumberUtil.div(NumberUtil.toBigDecimal(jvmFree),NumberUtil.toBigDecimal(1024 * 1024), 2));
        if(jvmUsed==0) {
            datas.set("jvmMemoryRate","0%");
        }else {
            datas.set("jvmMemoryRate", NumberUtil.mul(NumberUtil.toBigDecimal(jvmUsed).divide(NumberUtil.toBigDecimal(jvmTotal),2, RoundingMode.HALF_UP).doubleValue(), 100));
        }
        renderJBoltApiSuccessWithData(datas);
    }

    /**
     * 服务器基本信息监控
     */
    @JBoltHttpGet
    public void server() {
        Kv datas = Kv.create();
        OperatingSystem os = OshiUtil.getOs();
        System.out.println(JSON.toJSONString(os.getNetworkParams()));
        datas.set("serverHostName", StrKit.defaultIfBlank(os.getNetworkParams().getDomainName(),os.getNetworkParams().getHostName()));
        datas.set("serverOsName", os.toString());
        datas.set("serverOsArch", System.getProperty("os.arch"));
        datas.set("serverIp", JBoltIpUtil.getServerIp());
        datas.set("projectPath", System.getProperty("user.dir"));
        datas.set("dataCenterId", JBoltConfig.DATACENTER_ID);
        datas.set("workId", JBoltConfig.WORKER_ID);
        renderJBoltApiSuccessWithData(datas);
    }

    /**
     * jvm监控
     */
    @JBoltHttpGet
    public void jvm() {
        Kv datas = Kv.create();
        RuntimeMXBean runtimeMXBean= ManagementFactory.getRuntimeMXBean();
        datas.set("jvmName", runtimeMXBean.getVmName());
        datas.set("jvmVersion", runtimeMXBean.getVmVersion());
        datas.set("jvmHome",   System.getProperty("java.home"));
        Date startTime=new Date(runtimeMXBean.getStartTime());
        datas.set("jvmStarttime", JBoltDateUtil.format(startTime, JBoltDateUtil.YMDHMSS));
        datas.set("jvmRunUsedTime", JBoltDateUtil.getUsedTimeStr(startTime));
        renderJBoltApiSuccessWithData(datas);
    }

    /**
     * cpu监控
     */
    @JBoltHttpGet
    public void cpu() {
        Kv datas = Kv.create();
        CentralProcessor cpu=OshiUtil.getProcessor();
        datas.set("cpuName", cpu.getProcessorIdentifier().getName());
        datas.set("cpuCount", cpu.getPhysicalPackageCount()+"个 "+cpu.getPhysicalProcessorCount()+"核 "+cpu.getLogicalProcessorCount()+"线程");
        // CPU信息
        long[] prevTicks = cpu.getSystemCpuLoadTicks();
        Util.sleep(1000);
        long[] ticks = cpu.getSystemCpuLoadTicks();
        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        datas.set("cpuSystemUsed", NumberUtil.mul(NumberUtil.toBigDecimal(cSys).divide(NumberUtil.toBigDecimal(totalCpu),2, RoundingMode.HALF_UP).doubleValue(), 100));
        datas.set("cpuUserUsed", NumberUtil.mul(NumberUtil.toBigDecimal(user).divide(NumberUtil.toBigDecimal(totalCpu),2,RoundingMode.HALF_UP).doubleValue(), 100));
        datas.set("cpuWait", NumberUtil.mul(NumberUtil.toBigDecimal(iowait).divide(NumberUtil.toBigDecimal(totalCpu),2,RoundingMode.HALF_UP).doubleValue(), 100));
        datas.set("cpuFree", NumberUtil.mul(NumberUtil.toBigDecimal(idle).divide(NumberUtil.toBigDecimal(totalCpu),2,RoundingMode.HALF_UP).doubleValue(), 100));
        renderJBoltApiSuccessWithData(datas);
    }

    /**
     * 缓存监控
     */
    @JBoltHttpGet
    public void cache() {
        Kv datas = Kv.create();
        datas.set("cacheType",JBoltConfig.JBOLT_CACHE_TYPE);
        GroupedMap map = null;
        switch (JBoltConfig.JBOLT_CACHE_TYPE){
            case JBoltCacheType.CAFFEINE:
                map = JBoltConfig.caffeineSettings.getGroupedMap();

                break;
            case JBoltCacheType.REDIS:
                map =JBoltConfig.redisSettings.getGroupedMap();
                break;
        }
        datas.put("cacheMap",map);
        renderJBoltApiSuccessWithData(datas);
    }
}
